{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "83f7d689",
   "metadata": {},
   "source": [
    "# quantecon_book_networks\n",
    "\n",
    "## input_output\n",
    "\n",
    "### node_total_exports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6e1c0e01",
   "metadata": {},
   "outputs": [],
   "source": [
    "def node_total_exports(G):\n",
    "    node_exports = []\n",
    "    for node1 in G.nodes():\n",
    "        total_export = 0\n",
    "        for node2 in G[node1]:\n",
    "            total_export += G[node1][node2]['weight']\n",
    "        node_exports.append(total_export)\n",
    "    return node_exports"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d91edba5",
   "metadata": {},
   "source": [
    "### node_total_imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d7942abf",
   "metadata": {},
   "outputs": [],
   "source": [
    "def node_total_imports(G):\n",
    "    node_imports = []\n",
    "    for node1 in G.nodes():\n",
    "        total_import = 0\n",
    "        for node2 in G[node1]:\n",
    "            total_import += G[node2][node1]['weight']\n",
    "        node_imports.append(total_import)\n",
    "    return node_imports"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3dd8089f",
   "metadata": {},
   "source": [
    "### edge_weights"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fdf563f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def edge_weights(G):\n",
    "    edge_weights = [G[u][v]['weight'] for u,v in G.edges()]\n",
    "    return edge_weights"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "055dcff7",
   "metadata": {},
   "source": [
    "### normalise_weights"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54211ff8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def normalise_weights(weights,scalar=1):\n",
    "    max_value = np.max(weights)\n",
    "    return [scalar * (weight / max_value) for weight in weights]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfaedc3f",
   "metadata": {},
   "source": [
    "### to_zero_one"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ed795d06",
   "metadata": {},
   "outputs": [],
   "source": [
    "def to_zero_one(x):\n",
    "    \"Map vector x to the zero one interval.\"\n",
    "    x = np.array(x)\n",
    "    x_min, x_max = x.min(), x.max()\n",
    "    return (x - x_min)/(x_max - x_min)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ce4a5bd",
   "metadata": {},
   "source": [
    "### to_zero_one_beta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f2d51900",
   "metadata": {},
   "outputs": [],
   "source": [
    "def to_zero_one_beta(x, \n",
    "                qrange=[0.25, 0.75], \n",
    "                beta_para=[0.5, 0.5]):\n",
    "    \n",
    "    \"\"\"\n",
    "    Nonlinearly map vector x to the zero one interval with beta distribution.\n",
    "    https://en.wikipedia.org/wiki/Beta_distribution\n",
    "    \"\"\"\n",
    "    x = np.array(x)\n",
    "    x_min, x_max = x.min(), x.max()\n",
    "    if beta_para != None:\n",
    "        a, b = beta_para\n",
    "        return beta.cdf((x - x_min) /(x_max - x_min), a, b)\n",
    "    else:\n",
    "        q1, q2 = qrange\n",
    "        return (x - x_min) * (q2 - q1) /(x_max - x_min) + q1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "677a3b25",
   "metadata": {},
   "source": [
    "### colorise_weights"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "650554ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.cm as cm\n",
    "def colorise_weights(weights,beta=True,color_palette=cm.plasma):\n",
    "    if beta:\n",
    "        cp = color_palette(to_zero_one_beta(weights))\n",
    "    else:\n",
    "        cp = color_palette(to_zero_one(weights))\n",
    "    return cp "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13e770e7",
   "metadata": {},
   "source": [
    "### spec_rad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d31e595",
   "metadata": {},
   "outputs": [],
   "source": [
    "def spec_rad(M):\n",
    "    \"\"\"\n",
    "    Compute the spectral radius of M.\n",
    "    \"\"\"\n",
    "    return np.max(np.abs(np.linalg.eigvals(M)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b997a2b",
   "metadata": {},
   "source": [
    "### adjacency_matrix_to_graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b8660e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "def adjacency_matrix_to_graph(A, \n",
    "               codes,\n",
    "               tol=0.0):  # clip entries below tol\n",
    "    \"\"\"\n",
    "    Build a networkx graph object given an adjacency matrix\n",
    "    \"\"\"\n",
    "    G = nx.DiGraph()\n",
    "    N = len(A)\n",
    "\n",
    "    # Add nodes\n",
    "    for i, code in enumerate(codes):\n",
    "        G.add_node(code, name=code)\n",
    "\n",
    "    # Add the edges\n",
    "    for i in range(N):\n",
    "        for j in range(N):\n",
    "            a = A[i, j]\n",
    "            if a > tol:\n",
    "                G.add_edge(codes[i], codes[j], weight=a)\n",
    "\n",
    "    return G"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e673657f",
   "metadata": {},
   "source": [
    "### eigenvector_centrality"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90190208",
   "metadata": {},
   "outputs": [],
   "source": [
    "def eigenvector_centrality(A, k=40, authority=False):\n",
    "    \"\"\"\n",
    "    Computes the dominant eigenvector of A. Assumes A is \n",
    "    primitive and uses the power method.  \n",
    "    \"\"\"\n",
    "    A_temp = A.T if authority else A\n",
    "    n = len(A_temp)\n",
    "    r = spec_rad(A_temp)\n",
    "    e = r**(-k) * (np.linalg.matrix_power(A_temp, k) @ np.ones(n))\n",
    "    return e / np.sum(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78f99a4d",
   "metadata": {},
   "source": [
    "### katz_centrality"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "842342f6",
   "metadata": {},
   "outputs": [],
   "source": [
    "def katz_centrality(A, b=1, authority=False):\n",
    "    \"\"\"\n",
    "    Computes the Katz centrality of A, defined as the x solving\n",
    "\n",
    "    x = 1 + b A x    (1 = vector of ones)\n",
    "\n",
    "    Assumes that A is square.\n",
    "\n",
    "    If authority=True, then A is replaced by its transpose.\n",
    "    \"\"\"\n",
    "    n = len(A)\n",
    "    I = np.identity(n)\n",
    "    C = I - b * A.T if authority else I - b * A\n",
    "    return np.linalg.solve(C, np.ones(n))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76431864",
   "metadata": {},
   "source": [
    "### build_unweighted_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0e638e6a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def build_unweighted_matrix(Z, tol=1e-5):\n",
    "    \"\"\"\n",
    "    return a unweighted adjacency matrix\n",
    "    \"\"\"\n",
    "    return 1*(Z>tol)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db7270d9",
   "metadata": {},
   "source": [
    "### erdos_renyi_graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a74e9db",
   "metadata": {},
   "outputs": [],
   "source": [
    "def erdos_renyi_graph(n=100, p=0.5, seed=1234):\n",
    "    \"Returns an Erdős-Rényi random graph.\"\n",
    "    \n",
    "    np.random.seed(seed)\n",
    "    edges = itertools.combinations(range(n), 2)\n",
    "    G = nx.Graph()\n",
    "    \n",
    "    for e in edges:\n",
    "        if np.random.rand() < p:\n",
    "            G.add_edge(*e)\n",
    "    return G"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02443320",
   "metadata": {},
   "source": [
    "### build_coefficient_matrices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9316d715",
   "metadata": {},
   "outputs": [],
   "source": [
    "def build_coefficient_matrices(Z, X):\n",
    "    \"\"\"\n",
    "    Build coefficient matrices A and F from Z and X via \n",
    "    \n",
    "        A[i, j] = Z[i, j] / X[j] \n",
    "        F[i, j] = Z[i, j] / X[i]\n",
    "    \n",
    "    \"\"\"\n",
    "    A, F = np.empty_like(Z), np.empty_like(Z)\n",
    "    n = A.shape[0]\n",
    "    for i in range(n):\n",
    "        for j in range(n):\n",
    "            A[i, j] = Z[i, j] / X[j]\n",
    "            F[i, j] = Z[i, j] / X[i]\n",
    "\n",
    "    return A, F"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54010bf3",
   "metadata": {},
   "source": [
    "## plotting\n",
    "\n",
    "### plot_graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4439b087",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_graph(A, \n",
    "               X,\n",
    "               ax,\n",
    "               codes,\n",
    "               node_color_list=None,\n",
    "               node_size_multiple=0.0005, \n",
    "               edge_size_multiple=14,\n",
    "               layout_type='circular',\n",
    "               layout_seed=1234,\n",
    "               tol=0.03):  # clip entries below tol\n",
    "\n",
    "    G = nx.DiGraph()\n",
    "    N = len(A)\n",
    "\n",
    "    # Add nodes, with weights by sales of the sector\n",
    "    for i, w in enumerate(X):\n",
    "        G.add_node(codes[i], weight=w, name=codes[i])\n",
    "\n",
    "    node_sizes = X * node_size_multiple\n",
    "\n",
    "    # Position the nodes\n",
    "    if layout_type == 'circular':\n",
    "        node_pos_dict = nx.circular_layout(G)\n",
    "    elif layout_type == 'spring':\n",
    "        node_pos_dict = nx.spring_layout(G, seed=layout_seed)\n",
    "    elif layout_type == 'random':\n",
    "        node_pos_dict = nx.random_layout(G, seed=layout_seed)\n",
    "    elif layout_type == 'spiral':\n",
    "        node_pos_dict = nx.spiral_layout(G)\n",
    "\n",
    "    # Add the edges, along with their colors and widths\n",
    "    edge_colors = []\n",
    "    edge_widths = []\n",
    "    for i in range(N):\n",
    "        for j in range(N):\n",
    "            a = A[i, j]\n",
    "            if a > tol:\n",
    "                G.add_edge(codes[i], codes[j])\n",
    "                edge_colors.append(node_color_list[i])\n",
    "                width = a * edge_size_multiple\n",
    "                edge_widths.append(width)\n",
    "        \n",
    "    # Plot the networks\n",
    "    nx.draw_networkx_nodes(G, \n",
    "                           node_pos_dict, \n",
    "                           node_color=node_color_list, \n",
    "                           node_size=node_sizes, \n",
    "                           edgecolors='grey', \n",
    "                           linewidths=2, \n",
    "                           alpha=0.6, \n",
    "                           ax=ax)\n",
    "\n",
    "    nx.draw_networkx_labels(G, \n",
    "                            node_pos_dict, \n",
    "                            font_size=10, \n",
    "                            ax=ax)\n",
    "\n",
    "    nx.draw_networkx_edges(G, \n",
    "                           node_pos_dict, \n",
    "                           edge_color=edge_colors, \n",
    "                           width=edge_widths, \n",
    "                           arrows=True, \n",
    "                           arrowsize=20, \n",
    "                           alpha=0.6,  \n",
    "                           ax=ax, \n",
    "                           arrowstyle='->', \n",
    "                           node_size=node_sizes, \n",
    "                           connectionstyle='arc3,rad=0.15')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f879578e",
   "metadata": {},
   "source": [
    "### plot_matrices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e619a96",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_matrices(matrix,\n",
    "                  codes,\n",
    "                  ax,\n",
    "                  font_size=12,\n",
    "                  alpha=0.6, \n",
    "                  colormap=cm.viridis, \n",
    "                  color45d=None, \n",
    "                  xlabel='sector $j$', \n",
    "                  ylabel='sector $i$'):\n",
    "    \n",
    "    ticks = range(len(matrix))\n",
    "\n",
    "    levels = np.sqrt(np.linspace(0, 0.75, 100))\n",
    "    \n",
    "    \n",
    "    if color45d != None:\n",
    "        co = ax.contourf(ticks, \n",
    "                         ticks,\n",
    "                         matrix,\n",
    "#                          levels,\n",
    "                         alpha=alpha, cmap=colormap)\n",
    "        ax.plot(ticks, ticks, color=color45d)\n",
    "    else:\n",
    "        co = ax.contourf(ticks, \n",
    "                         ticks,\n",
    "                         matrix,\n",
    "                         levels,\n",
    "                         alpha=alpha, cmap=colormap)\n",
    "\n",
    "    #plt.colorbar(co)\n",
    "\n",
    "    ax.set_xlabel(xlabel, fontsize=font_size)\n",
    "    ax.set_ylabel(ylabel, fontsize=font_size)\n",
    "    ax.set_yticks(ticks)\n",
    "    ax.set_yticklabels(codes)\n",
    "    ax.set_xticks(ticks)\n",
    "    ax.set_xticklabels(codes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88631141",
   "metadata": {},
   "source": [
    "### unit_simplex"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f4de6b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "def unit_simplex(angle):\n",
    "    \n",
    "    fig = plt.figure(figsize=(10, 8))\n",
    "    ax = fig.add_subplot(111, projection='3d')\n",
    "\n",
    "    vtx = [[0, 0, 1],\n",
    "           [0, 1, 0], \n",
    "           [1, 0, 0]]\n",
    "    \n",
    "    tri = Poly3DCollection([vtx], color='darkblue', alpha=0.3)\n",
    "    tri.set_facecolor([0.5, 0.5, 1])\n",
    "    ax.add_collection3d(tri)\n",
    "\n",
    "    ax.set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), \n",
    "           xticks=(1,), yticks=(1,), zticks=(1,))\n",
    "\n",
    "    ax.set_xticklabels(['$(1, 0, 0)$'], fontsize=16)\n",
    "    ax.set_yticklabels([f'$(0, 1, 0)$'], fontsize=16)\n",
    "    ax.set_zticklabels([f'$(0, 0, 1)$'], fontsize=16)\n",
    "\n",
    "    ax.xaxis.majorTicks[0].set_pad(15)\n",
    "    ax.yaxis.majorTicks[0].set_pad(15)\n",
    "    ax.zaxis.majorTicks[0].set_pad(35)\n",
    "\n",
    "    ax.view_init(30, angle)\n",
    "\n",
    "    # Move axis to origin\n",
    "    ax.xaxis._axinfo['juggled'] = (0, 0, 0)\n",
    "    ax.yaxis._axinfo['juggled'] = (1, 1, 1)\n",
    "    ax.zaxis._axinfo['juggled'] = (2, 2, 0)\n",
    "    \n",
    "    ax.grid(False)\n",
    "    \n",
    "    return ax"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
